package cn.lili.modules.order.payment;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.thread.ThreadConfig;
import cn.lili.common.utils.DateUtil;
import cn.lili.modules.goods.client.GoodsSkuClient;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.order.order.entity.dos.*;
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
import cn.lili.modules.order.order.entity.vo.TradeCashierParamVO;
import cn.lili.modules.order.order.service.*;
import cn.lili.modules.payment.entity.dos.PaymentLog;
import cn.lili.modules.payment.entity.dto.PayParam;
import cn.lili.modules.payment.entity.dto.PayParamItem;
import cn.lili.modules.payment.entity.dto.PaymentCallback;
import cn.lili.modules.payment.entity.enums.PaymentClientEnum;
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
import cn.lili.modules.payment.entity.enums.PaymentSceneEnums;
import cn.lili.modules.system.client.SettingClient;
import cn.lili.modules.system.client.SmsClient;
import cn.lili.modules.system.entity.dto.BaseSetting;
import cn.lili.modules.system.entity.dto.OrderSetting;
import cn.lili.modules.system.entity.enums.SettingEnum;
import cn.lili.modules.system.entity.params.SmsParams;
import cn.lili.modules.verification.entity.enums.VerificationEnums;
import cn.lili.util.ToolsUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 交易收银台
 *
 * @author Chopper
 * @since 2021-01-25 20:00
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class TradeCashier {

    /**
     * 交易
     */
    private final TradeService tradeService;

    /**
     * 订单
     */
    private final OrderService orderService;
    private final OrderItemService orderItemService;
    private final GoodsSkuClient goodsSkuClient;
    /**
     * 设置
     */
    private final SettingClient settingClient;

    private final VipOrderService vipOrderService;
    private final ThreadConfig threadConfig;
    private final IPaymentCallbackOrderLogService paymentCallbackOrderLogService;
    private final SmsClient smsClient;
    /**
     * 加工付款VO
     *
     * @param sn                  交易编号
     * @param tradeCashierParamVO 订单收银台参数
     * @return 支付参数
     */
    public TradeCashierParamVO handlerCashierParams(String sn, TradeCashierParamVO tradeCashierParamVO) {
        //订单信息获取
        Trade trade = tradeService.getBySn(sn);

        List<Order> orders = orderService.getByTradeSn(sn);
        //交易有效性判定
        if (trade == null || orders == null || orders.isEmpty()) {
            throw new ServiceException(ResultCode.PAY_NOT_EXIST_ORDER);
        }
        //订单信息获取
        String orderSns = orders.stream().map(Order::getSn).collect(Collectors.joining(", "));
        tradeCashierParamVO.setOrderSns(orderSns);
        boolean isBlindBox = false;
        boolean isFree = false;
        String orderSn = "";
        for (Order order : orders) {
            System.out.println(order.getOrderStatus());
            //如果订单状态不是待付款，则抛出异常
            if (!order.getOrderStatus().equals(OrderStatusEnum.UNPAID.name())) {
                throw new ServiceException(ResultCode.PAY_BAN);
            }
            if (order.getIsDutyFree()!=null && order.getIsDutyFree()) {
                isFree = true;
            }
            orderSn = order.getSn();
        }
        OrderItem orderItem = orderItemService.getOne(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderSn, orderSn).last("limit 1"));
        if (orderItem != null && StringUtil.isNotEmpty(orderItem.getSkuId())) {
            GoodsSku goodsSku = goodsSkuClient.getGoodsSkuById(orderItem.getSkuId());
            if (goodsSku != null && StringUtil.isNotEmpty(goodsSku.getMhId())) {
                isBlindBox = true;
            }
        }
        tradeCashierParamVO.setPrice(trade.getFlowPrice());
        tradeCashierParamVO.setIsBlindBox(isBlindBox);
        tradeCashierParamVO.setIsFree(isFree);
        try {
            BaseSetting baseSetting = JSONUtil.toBean(settingClient.get(SettingEnum.BASE_SETTING.name()).getSettingValue(), BaseSetting.class);
            tradeCashierParamVO.setTitle(baseSetting.getSiteName());
        } catch (Exception e) {
            tradeCashierParamVO.setTitle("多用户商城，在线支付");
        }
        String subject = "在线支付";
        tradeCashierParamVO.setDetail(subject);

        tradeCashierParamVO.setCreateTime(trade.getCreateTime());

        try {

            tradeCashierParamVO.setAutoCancel(DateUtil.offsetMinute(trade.getCreateTime(), getAutoCancelTime()).getTime());
        } catch (Exception e) {
            tradeCashierParamVO.setAutoCancel(0L);
        }
        return tradeCashierParamVO;
    }


    /**
     * 生成支付参数
     *
     * @param tradeSn 交易编号
     * @return 支付参数
     */
    public PayParam generatePaymentParams(String tradeSn, PaymentClientEnum paymentClientEnum, PaymentMethodEnum paymentMethodEnum) {
        // 支付参数
        Trade trade = tradeService.getBySn(tradeSn);
        log.info("支付参数--trade--{}",trade);

        //交易有效性判定
        assert trade != null;


        // 支付参数
        List<PayParamItem> payParamItems = new ArrayList<>();
        orderService.getByTradeSn(tradeSn).forEach(order -> {
            PayParamItem payParamItem = PayParamItem.builder()
                    .sn(order.getSn())
                    .price(order.getFlowPrice())
                    .payeeId(order.getStoreId())
                    .description(order.getStoreName())
                    .specialOrder(false)
                    .build();

            //如果订单结算金额为负数，则为特殊订单
            if (order.getPriceDetailDTO().getPlatformSettlementPrice() < 0
                    || order.getPriceDetailDTO().getSellerSettlementPrice() < 0
                    || order.getPriceDetailDTO().getSupplierSettlementPrice() < 0) {
                payParamItem.setSpecialOrder(true);
            }

            payParamItems.add(payParamItem);
        });

        log.info("支付参数--payParamItems--{}", JSON.toJSONString(payParamItems));

        return PayParam.builder()
                .payerId(UserContext.getCurrentId())
                .combineSn(trade.getSn())
                .paymentClientEnum(paymentClientEnum)
                .paymentMethodEnum(paymentMethodEnum)
                .payParamItems(payParamItems)
                .timeoutExpress(getAutoCancelTime())
                .build();
    }

    /**
     * 支付成功
     *
     * @param paymentCallback 支付回调
     */
    public void paymentCallback(PaymentCallback paymentCallback) {
        try {
            tradeService.payTrade(paymentCallback);
        } catch (Exception e) {
            log.info("支付回调订单处理 try catch 捕获错误, #paymentCallback# 报错,发送短信通知,", e);
            Objects.requireNonNull(threadConfig.getAsyncExecutor()).execute(() -> {
                Order o = null;
                //保存日志并处理订单
                if (Boolean.TRUE.equals(paymentCallback.getIsCombine())) {
                    List<PaymentCallbackOrderLog> logList = new ArrayList<>();
                    //合单情况
                    for (PaymentLog paymentLog : paymentCallback.getPaymentLogs()) {
                        PaymentCallbackOrderLog callbackOrderLog = new PaymentCallbackOrderLog();
                        callbackOrderLog.setOutTradeOn("1支付回调订单处理 try catch 捕获错误, #paymentCallback# 报错");
                        callbackOrderLog.setOrderSn(paymentLog.getOrderSn());
                        callbackOrderLog.setMethodName("2支付回调订单处理 TradeCashier.paymentCallback");
                        logList.add(callbackOrderLog);
                        //补偿处理订单
                        o = new Order();
                        o.setSn(paymentLog.getOrderSn());
                        orderService.handlePayNotSuccessOrder(o);
                    }
                    logList.get(0).setParams("3支付回调订单处理 try catch 捕获错误:--->" + ToolsUtil.getExceptionSrintStackTrace(e));
                    paymentCallbackOrderLogService.saveBatch(logList);
                } else {
                    //普通订单
                    PaymentCallbackOrderLog callbackOrderLog = new PaymentCallbackOrderLog();
                    callbackOrderLog.setOutTradeOn("1支付回调订单处理 try catch 捕获错误, #paymentCallback# 报错");
                    callbackOrderLog.setOrderSn(paymentCallback.getPaymentLog().getOrderSn());
                    callbackOrderLog.setMethodName("2支付回调订单处理 TradeCashier.paymentCallback");
                    callbackOrderLog.setParams("支付回调订单处理 try catch 捕获错误:--->" + ToolsUtil.getExceptionSrintStackTrace(e));
                    paymentCallbackOrderLogService.save(callbackOrderLog);
                    //补偿处理订单
                    o = new Order();
                    o.setSn(paymentCallback.getPaymentLog().getOrderSn());
                    orderService.handlePayNotSuccessOrder(o);
                }
            });
        }
        log.info("支付回调订单处理 完毕,未捕获到异常");
    }

    /**
     * 获取自动取消时间
     *
     * @return 自动取消时间
     */
    private Integer getAutoCancelTime() {
        OrderSetting orderSetting = JSONUtil.toBean(settingClient.get(SettingEnum.ORDER_SETTING.name()).getSettingValue(), OrderSetting.class);
        return orderSetting.getAutoCancel();
    }

    /**
     * 生成支付参数
     *
     * @return 支付参数
     */
    public PayParam generatePaymentBySceneParams(String sn, PaymentSceneEnums paymentSceneEnums,
                                                 PaymentClientEnum paymentClientEnum,
                                                 PaymentMethodEnum paymentMethodEnum) {
        VipOrder vipOrder = vipOrderService.getBySn(sn);
        if (vipOrder == null) {
            throw new ServiceException(ResultCode.PAY_NOT_EXIST_ORDER);
        }
        if (!vipOrder.getOrderStatus().equals(OrderStatusEnum.UNPAID.name())) {
            throw new ServiceException(ResultCode.PAY_BAN);
        }
        List<PayParamItem> payParamItems = new ArrayList<>();
        PayParamItem payParamItem = PayParamItem.builder()
                .sn(vipOrder.getSn())
                .price(vipOrder.getFlowPrice())
                .payeeId("-1")
                .specialOrder(false)
                .description(vipOrder.getNickname())
                .build();
        payParamItems.add(payParamItem);
        return PayParam.builder()
                .payerId(UserContext.getCurrentId())
                .payParamItems(payParamItems)
                .combineSn(sn)
                .paymentClientEnum(paymentClientEnum)
                .paymentMethodEnum(paymentMethodEnum)
                .paymentSceneEnums(paymentSceneEnums)
                .timeoutExpress(getAutoCancelTime())
                .build();
    }

    /**
     * 当最近的一笔未支付的订单是，免税订单，只展示微信支付
     * @param result
     */
    public void filterSupport(TradeCashierParamVO result) {
        if (result.getIsFree() != null && result.getIsFree()) {
            result.setSupport(result.getSupport().stream().filter(s -> s.equals(PaymentMethodEnum.WECHAT.name())).collect(Collectors.toList()));
            if (CollectionUtil.isEmpty(result.getSupport())) {
                throw new ServiceException("是免税订单，但没有微信支付");
            }
        }
    }
}